# @Time : 2021/6/24 22:30
# @Author : Tesla
# @File : 13.修改本地连接mac地址.py
# @Software: PyCharm
# Csdn : https://blog.csdn.net/zhu6201976

import ctypes
import os
import platform
import re
import subprocess
import sys
import time
import winreg


class SetMac(object):
    """
    修改 本地连接 mac地址
    """

    def __init__(self):
        # regex to MAC address like 00-00-00-00-00-00 or 00:00:00:00:00:00 or
        # 000000000000
        self.MAC_ADDRESS_RE = re.compile(r"""
            ([0-9A-F]{1,2})[:-]?
            ([0-9A-F]{1,2})[:-]?
            ([0-9A-F]{1,2})[:-]?
            ([0-9A-F]{1,2})[:-]?
            ([0-9A-F]{1,2})[:-]?
            ([0-9A-F]{1,2})
            """, re.I | re.VERBOSE)  # re.I: case-insensitive matching. re.VERBOSE: just look nicer.

        self.WIN_REGISTRY_PATH = "SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}"

    def is_admin(self):
        """
        is user an admin?
        :return:
        """
        if ctypes.windll.shell32.IsUserAnAdmin() == 0:
            print('Sorry! You should run this with administrative privileges if you want to change your MAC address.')
            sys.exit()
        else:
            print('admin')

    def get_macinfos(self):
        """
        查看所有mac信息
        :return:
        """
        print('=' * 50)
        mac_info = subprocess.check_output('GETMAC /v /FO list', stderr=subprocess.STDOUT)
        mac_info = mac_info.decode('gbk')
        print('Your MAC address:\n', mac_info)

    def get_target_device(self, netCard):
        """
        返回 本地连接 网络适配器
        :return:
        """
        mac_info = subprocess.check_output('GETMAC /v /FO list', stderr=subprocess.STDOUT)
        mac_info = mac_info.decode('gbk')
        search = re.search(r'({netCard})\s+网络适配器: (.+)\s+物理地址:'.format(netCard=netCard), mac_info)

        target_name, target_device = (search.group(1), search.group(2).strip()) if search else ('', '')
        print(target_name, target_device)
        print("*"*29)
        if not all([target_name, target_device]):
            print('Cannot find the target device')
            sys.exit()

        print(target_name, target_device)
        return target_device

    def set_mac_address(self, target_device, new_mac):
        """
        设置新mac地址
        :param target_device: 本地连接 网络适配器
        :param new_mac: 新mac地址
        :return:
        """
        if not self.MAC_ADDRESS_RE.match(new_mac):
            print('Please input a correct MAC address')
            return

        # Locate adapter's registry and update network address (mac)
        reg_hdl = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
        key = winreg.OpenKey(reg_hdl, self.WIN_REGISTRY_PATH)
        info = winreg.QueryInfoKey(key)

        # Find adapter key based on sub keys
        adapter_key = None
        adapter_path = None
        target_index = -1

        for index in range(info[0]):
            subkey = winreg.EnumKey(key, index)
            path = self.WIN_REGISTRY_PATH + "\\" + subkey

            if subkey == 'Properties':
                break

            # Check for adapter match for appropriate interface
            new_key = winreg.OpenKey(reg_hdl, path)
            try:
                adapterDesc = winreg.QueryValueEx(new_key, "DriverDesc")
                if adapterDesc[0] == target_device:
                    adapter_path = path
                    target_index = index
                    break
                else:
                    winreg.CloseKey(new_key)
            except (WindowsError) as err:
                if err.errno == 2:  # register value not found, ok to ignore
                    pass
                else:
                    raise err

        if adapter_path is None:
            print('Device not found.')
            winreg.CloseKey(key)
            winreg.CloseKey(reg_hdl)
            return

        # Registry path found update mac addr
        adapter_key = winreg.OpenKey(reg_hdl, adapter_path, 0, winreg.KEY_WRITE)
        winreg.SetValueEx(adapter_key, "NetworkAddress", 0, winreg.REG_SZ, new_mac)
        winreg.CloseKey(adapter_key)
        winreg.CloseKey(key)
        winreg.CloseKey(reg_hdl)

        # Adapter must be restarted in order for change to take affect
        # print 'Now you should restart your netsh'
        self.restart_adapter(target_index, target_device)

    def restart_adapter(self, target_index, target_device):
        """
        Disables and then re-enables device interface
        """
        if platform.release() == 'XP':
            # description, adapter_name, address, current_address = find_interface(device)
            cmd = "devcon hwids =net"
            try:
                result = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
            except FileNotFoundError:
                raise
            query = '(' + target_device + '\r\n\s*.*:\r\n\s*)PCI\\\\(([A-Z]|[0-9]|_|&)*)'
            query = query.encode('ascii')
            match = re.search(query, result)
            cmd = 'devcon restart "PCI\\' + str(match.group(2).decode('ascii')) + '"'
            subprocess.check_output(cmd, stderr=subprocess.STDOUT)
        else:
            cmd = "wmic path win32_networkadapter where index=" + str(target_index) + " call disable"
            subprocess.check_output(cmd)
            cmd = "wmic path win32_networkadapter where index=" + str(target_index) + " call enable"
            subprocess.check_output(cmd)

    def run(self,mac,netCard):
        self.is_admin()
        self.get_macinfos()
        target_device = self.get_target_device(netCard)
        self.set_mac_address(target_device, mac)
        self.get_macinfos()

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False
def admin_set(set_mac,mac) :
    if is_admin():
        print("admin_exe函数内，以管理员权限运行")
        set_mac.run(mac)
    else:
        if sys.version_info[0] == 3:
            print('admin_exe函数内，还没有管理员权限')
            ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)

def admin_clear() :
    if is_admin():
        res = os.system("arp -d")
        return True
    else:
        if sys.version_info[0] == 3:
            ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
            return False

def mac_splite(mac):
    mac_list = mac.split(':')
    new_mac = ""
    for i, mac in enumerate(mac_list):
        if i < 6:
            if len(mac) == 0:
                pass
                return False
            else:
                new_mac += mac
    return new_mac

if __name__ == '__main__':
    set_mac = SetMac()

    # print(admin_exe())
    if is_admin():
        mac = '3CEB9085031E'
        set_mac.run(mac)
        time.sleep()
    else:
        if sys.version_info[0] == 3:
            ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)

    # res = mac_splite("11:22")
    # print(res)
    # res = admin_clear()
    # print(res)

